package dy.com.第6六章简易聊天室.simpleServer.Server.handler;

import dy.com.收发并行.Util.CloseUtils;

import java.io.*;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ClientHandler {
    Socket clientSocket = null;
    private ClientHandlerCallback clientHandlerCallback;
    ClientReadHandler clientReadHandler = null;
    ClientWriteHandler clientWriteHandler = null;
    private final String clientInfo;

    public ClientHandler(Socket clientSocket, ClientHandlerCallback clientHandlerCallback) throws IOException {
        this.clientSocket = clientSocket;
        System.out.println("开始处理新的客户端连接:" + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
        clientReadHandler = new ClientReadHandler(clientSocket.getInputStream());
        clientWriteHandler = new ClientWriteHandler(clientSocket.getOutputStream());
        this.clientHandlerCallback = clientHandlerCallback;
        this.clientInfo = "地址["+clientSocket.getInetAddress()+"]"
                        +"端口["+clientSocket.getPort()+"]";
        System.out.println("新客户端连接："+this.clientInfo);
    }

    public String getClientInfo() {
        return clientInfo;
    }

    public void exit() {
        clientReadHandler.exit();
        clientWriteHandler.exit();
        CloseUtils.close(clientSocket);
        System.out.println("客户端已退出：" + clientSocket.getInetAddress() +
                " P:" + clientSocket.getPort());
    }

    private void exitBySelf() {
        exit();
        clientHandlerCallback.onSelfClosed(this);
    }
    //接口回调
    public interface ClientHandlerCallback {
        //当自己把自己关闭后，让外面的类消除自己
        void onSelfClosed(ClientHandler clientHandler);
        void onNewMessageArrived(ClientHandler clientHandler,String msg);
    }

    public void readAndPrint() {
        clientReadHandler.start();
    }

    public void send(String str) {
        clientWriteHandler.send(str);
    }

    //读线程
    private class ClientReadHandler extends Thread {
        private boolean finish;
        private InputStream inputStream;

        ClientReadHandler(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        public void run() {

            try {
                //得到缓存reader
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));


                while (!finish) {
                    String s = bufferedReader.readLine();
                    if (s == null) {
                        System.out.println("客户端已无法读取数据");
                        //退出当前客户端
                        ClientHandler.this.exitBySelf();
                        break;
                    } else {
                        //打印到屏幕
                        //System.out.println(s);
                        //把自己传递回去通知
                        clientHandlerCallback.onNewMessageArrived(ClientHandler.this,s);
                    }
                }
                bufferedReader.close();


            } catch (IOException e) {
                if (!finish) {
                    System.out.println("异常断开");
                    ClientHandler.this.exitBySelf();
                    //e.printStackTrace();
                }
            } finally {
                CloseUtils.close(inputStream);

            }
        }

        void exit() {
            finish = true;
            CloseUtils.close(inputStream);
        }
    }


    //写线程
    private class ClientWriteHandler {
        private PrintStream printStream;
        private boolean finish;
        private ExecutorService executorService;

        public ClientWriteHandler(OutputStream outputStream) {
            this.printStream = new PrintStream(outputStream);
            executorService = Executors.newSingleThreadExecutor();

        }


        void send(String str) {
            if(finish){
                return;
            }
            executorService.execute(new WriteRunnable(str));
        }

        public void exit() {
            finish = true;
            CloseUtils.close(printStream);
            executorService.shutdown();
        }

        class WriteRunnable implements Runnable {
            String str;

            WriteRunnable(String str) {
                this.str = str;
            }

            @Override
            public void run() {
                if (ClientHandler.ClientWriteHandler.this.finish) {
                    return;
                }
                ClientHandler.ClientWriteHandler.this.printStream.println(str);
            }
        }
    }
}
